﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using InvoiceSample;
using CodeProject.Data.Entity;
using System.Data.Objects;

namespace TestProjectCS
{
	public class BaseInvoiceTests
	{
		#region Helper methods

		protected void ResetCaches()
		{
			this._contactsCache = null;
			this._productsCache = null;
		}

		private Dictionary<long, Contact> _contactsCache;

		protected Dictionary<long, Contact> Contacts
		{
			get
			{
				if (_contactsCache == null)
				{
					var result = new Dictionary<long, Contact>();

					using (var context = new SampleInvoiceContext())
					{
						context.ContactSet.MergeOption = MergeOption.NoTracking;

						foreach (var item in context.ContactSet)
							result[item.ID] = item;
					}

					_contactsCache = result;
				}

				return _contactsCache;
			}
		}

		protected Dictionary<long, Customer> Customers
		{
			get 
			{
				var result = new Dictionary<long, Customer>();
				foreach (Contact item in this.Contacts.Values)
					if (item is Customer)
						result[item.ID] = (Customer)item;
				return result;
			}
		}

		protected Dictionary<long, Supplier> Suppliers
		{
			get
			{
				var result = new Dictionary<long, Supplier>();
				foreach (Contact item in this.Contacts.Values)
					if (item is Supplier)
						result[item.ID] = (Supplier)item;
				return result;
			}
		}

		private Dictionary<long, Product> _productsCache;

		protected Dictionary<long, Product> Products
		{
			get
			{
				if (_productsCache == null)
				{
					var result = new Dictionary<long, Product>();

					using (var context = new SampleInvoiceContext())
					{
						context.ProductSet.MergeOption = MergeOption.NoTracking;

						foreach (var item in context.ProductSet)
							result[item.ID] = item;
					}

					_productsCache = result;
				}

				return _productsCache;
			}
		}

		protected Invoice GetDetachedInvoice(long ID)
		{
			using (var context = new SampleInvoiceContext())
			{
				var invq = from inv
						   in context.InvoiceSet
								.Include(p => p.Customer)
								.Include(p => p.Lines.First().Product.Supplier)
						   where inv.Identifier == ID
						   select inv;
				return context.DetachObjectGraph(invq.First());
			}
		}

		protected Product GetDetachedProductWithSupplier(long ID)
		{
			using (var context = new SampleInvoiceContext())
			{
				var prodq = from prod
							in context.ProductSet
								.Include(p => p.Supplier)
							where prod.ID == ID
							select prod;
				return context.DetachObjectGraph(prodq.First());
			}
		}

		protected void ShowInvoice(Invoice inv, string title)
		{
			Console.WriteLine();
			if (title != null)
				Console.WriteLine(title);
			if (inv == null)
				Console.WriteLine("Invoice: null");
			else
			{
				Console.WriteLine("Invoice: {0}, {1} ({2}, {3}) => {4}", inv.Identifier, inv.InvoiceDate, inv.EntityState, inv.LastChanged, inv.TotalPrice);
				if (inv.Customer != null)
					Console.WriteLine("Customer: {0}, {1} ({2}, {3})", inv.Customer.ID, inv.Customer.Name, inv.Customer.EntityState, inv.Customer.LastChanged);
				if (inv.Lines != null)
				{
					Console.WriteLine("Lines: {0}", inv.Lines.Count);
					foreach (InvoiceLine line in inv.Lines)
					{
						Console.WriteLine("- Line: {0}, {1} x €{2} ({3}, {4})", line.ID, line.Quantity, line.UnitPrice, line.EntityState, line.LastChanged);
						if (line.Product != null)
						{
							Console.WriteLine("  Product: {0}, {1} ({2}, {3})", line.Product.ID, line.Product.Label, line.Product.EntityState, line.Product.LastChanged);
							if (line.Product.Supplier != null)
								Console.WriteLine("  Supplier: {0}, {1} ({2}, {3})", line.Product.Supplier.ID, line.Product.Supplier.Name, line.Product.Supplier.EntityState, line.Product.Supplier.LastChanged);
						}
					}
				}
			}
		}

		#endregion

		#region Custom asserts

		protected void AssertContextChanges(ObjectContext context, int additions, int modifications, int deletions)
		{
			Assert.AreEqual(additions, context.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Added).Count(), "Context additions mismatch.");
			Assert.AreEqual(modifications, context.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Modified).Count(), "Context modifications mismatch.");
			Assert.AreEqual(deletions, context.ObjectStateManager.GetObjectStateEntries(System.Data.EntityState.Deleted).Count(), "Context deletions mismatch.");
		}

		#endregion
	}
}
